package com.csw.android.androidtest.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import com.csw.android.dev_utils.utils.ScreenInfo;

import java.util.Arrays;

public class TouchView extends View {
    private static final int DEFAULT_COLOR = Color.YELLOW;
    private OnPointInfoUpdateListener onPointInfoUpdateListener;
    private final int[] pointColor = new int[10];
    private final PointInfo[] pointInfos = new PointInfo[10];
    private final float pointSize = ScreenInfo.INSTANCE.dp2Px(48);
    private final Paint pointPaint = new Paint();

    public TouchView(Context context) {
        this(context, null);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setPointColor(DEFAULT_COLOR);
        //抗锯齿
        pointPaint.setAntiAlias(true);
        pointPaint.setStrokeWidth(1);
        pointPaint.setStyle(Paint.Style.FILL);
        //动态模糊
        pointPaint.setDither(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (PointInfo p : pointInfos) {
            if (p != null) {
                pointPaint.setColor(p.color);
                canvas.drawCircle(p.x, p.y, pointSize / 2, pointPaint);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int pointId = event.getPointerId(event.getActionIndex());
        float x = event.getX(event.getActionIndex());
        float y = event.getY(event.getActionIndex());
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                clearPoint();
                noticePointInfo(new PointInfo(pointId, x, y, 1, pointColor[pointId]));
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                noticePointInfo(new PointInfo(pointId, x, y, 1, pointColor[pointId]));
                break;
            case MotionEvent.ACTION_MOVE:
                int pI;
                PointInfo pointInfo;
                float pX;
                float pY;
                if (event.getHistorySize() > 0) {
                    for (int i = 0; i < event.getPointerCount(); i++) {
                        pI = event.getPointerId(i);
                        pX = event.getHistoricalX(i, 0);
                        pY = event.getHistoricalY(i, 0);
                        pointInfo = pointInfos[pI];
                        if (pointInfo != null) {
                            if (pointInfo.x != pX || pointInfo.y != pY) {
                                noticePointInfo(new PointInfo(pI, pX, pY, 2, pointColor[pI]));
                            }
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                noticePointInfo(new PointInfo(pointId, x, y, 3, pointColor[pointId]));
                break;
            case MotionEvent.ACTION_UP:
                noticePointInfo(new PointInfo(pointId, x, y, 3, pointColor[pointId]));
                noticeClearPoint();
                break;
        }
        return true;
    }

    private void noticeClearPoint() {
        if (onPointInfoUpdateListener != null) {
            onPointInfoUpdateListener.onClearPointInfos();
        }
        clearPoint();
    }

    public void clearPoint() {
        Arrays.fill(pointInfos, null);
        postInvalidate();
    }

    public void noticePointInfo(PointInfo pointInfo) {
        if (onPointInfoUpdateListener != null) {
            onPointInfoUpdateListener.onPointInfoUpdate(pointInfo);
        }
        setPointInfo(pointInfo);
    }

    public void setPointInfo(PointInfo pointInfo) {
        if (pointInfo.state == 3) {
            pointInfos[pointInfo.pointId] = null;
        } else {
            pointInfos[pointInfo.pointId] = pointInfo;
        }
        postInvalidate();
    }

    public void setPointColor(int color) {
        int a = Color.alpha(color);
        int r = Color.red(color);
        int g = Color.green(color);
        int b = Color.blue(color);
        float p;
        for (int i = 1; i <= pointColor.length; i++) {
            p = i * 1f / pointColor.length;
            pointColor[pointColor.length - i] = Color.argb(a, (int) (r * p), (int) (g * p), (int) (b * p));
        }
        postInvalidate();
    }

    public void setOnPointInfoUpdateListener(OnPointInfoUpdateListener onPointInfoUpdateListener) {
        this.onPointInfoUpdateListener = onPointInfoUpdateListener;
    }

    public interface OnPointInfoUpdateListener {
        void onPointInfoUpdate(PointInfo pointInfo);

        void onClearPointInfos();
    }

    public static class PointInfo {
        private int pointId;
        private float x;
        private float y;
        //1down，2move，3up
        private int state;
        private int color;

        public PointInfo(int pointId, float x, float y, int state, int color) {
            this.pointId = pointId;
            this.x = x;
            this.y = y;
            this.state = state;
            this.color = color;
        }

        public int getPointId() {
            return pointId;
        }

        public void setPointId(int pointId) {
            this.pointId = pointId;
        }

        public float getX() {
            return x;
        }

        public void setX(float x) {
            this.x = x;
        }

        public float getY() {
            return y;
        }

        public void setY(float y) {
            this.y = y;
        }

        public int getState() {
            return state;
        }

        public void setState(int state) {
            this.state = state;
        }

        public int getColor() {
            return color;
        }

        public void setColor(int color) {
            this.color = color;
        }
    }

}
